
#include "RandLib.h"
#include "RenderingManager.h"
#include <iostream>
#include <ctime>

#define MODULUS    2147483647 /* DON'T CHANGE THIS VALUE                  */
#define MULTIPLIER 48271      /* DON'T CHANGE THIS VALUE                  */
#define CHECK      399268537  /* DON'T CHANGE THIS VALUE                  */
#define A256       22925      /* jump multiplier, DON'T CHANGE THIS VALUE */
#define DEFAULT    static_cast<unsigned long> (time(static_cast<time_t *> (NULL)))%MODULUS /* initial seed, use 0 < DEFAULT < MODULUS  */

static long seed = DEFAULT; /* current state of each stream   */

// <editor-fold defaultstate="collapsed" desc="Generator core functions">
namespace ParkMillerRNG
{

/* ===========================================================
 * Returns a uniformly distributed real number between a and b.
 * NOTE: use a < b
 * ===========================================================
 */
double Uniform(double a, double b)
{
    return (a + (b - a) * Random());
}

/* ===================================================================
 * Returns an equilikely distributed integer between a and b inclusive.
 * NOTE: use a < b
 * ===================================================================
 */
long Equilikely(long a, long b)
{
    return (a + static_cast<long> ((b - a + 1) * Random()));
}

/* ----------------------------------------------------------------
 * Random returns a pseudo-random real number uniformly distributed
 * between 0.0 and 1.0.
 * ----------------------------------------------------------------
 */
double Random(void)
{
    const long Q = MODULUS / MULTIPLIER;
    const long R = MODULUS % MULTIPLIER;
    long t;

    t = MULTIPLIER * (seed % Q) - R * (seed / Q);
    if (t > 0)
        seed = t;
    else
        seed = t + MODULUS;
    return (static_cast<double> (seed) / MODULUS);
}
}
// </editor-fold>

namespace Math
{

/* ---------------------------------------------------------------
 * Modified version of PutSeed(long x) of the Park-Miller RNG
 * Reinitializes the seed
 * ---------------------------------------------------------------
 */
void ReinitRand(long x = 0)
{
    if (x > 0)
        x = x % MODULUS; /* correct if x is too large */
    if (x <= 0)
        x = (static_cast<unsigned long> (time(static_cast<time_t *> (NULL)))) % MODULUS;
    seed = x;
}

int Random(int min, int max)
{
    return ParkMillerRNG::Equilikely(static_cast<long> (min), static_cast<long> (max));
}

float Random(float min, float max)
{
    return ParkMillerRNG::Uniform(static_cast<double> (min), static_cast<double> (max));
}

double Random(double min, double max)
{
    return ParkMillerRNG::Uniform(static_cast<double> (min), static_cast<double> (max));
}

Math::Vector2F Random(const Math::Vector2F& min, const Math::Vector2F& max)
{
    using namespace ParkMillerRNG;
    return Math::Vector2F( Uniform(static_cast<double> (min.GetX()) , static_cast<double> (max.GetX())),
                          Uniform(static_cast<double> (min.GetY()) , static_cast<double> (max.GetY())) );
}

/* --------------------------------------------------------------
 * Gets the chance of an event happening and returns true
 * if it happened, or false if it didn't.
 * (chance>=1 -> event happens for sure | chance<=0 -> event never happens)
 * --------------------------------------------------------------
 */
bool EventCheck(float chance)
{
    if (chance >= 1)
        return true;
    else if (chance <= 0)
        return false;
    else
    {
        if (Random(0.0, 1.0) <= chance)
            return true;
        else
            return false;
    }
}

}

